#include "../stdafx.h"
#include "Notify.h"

#include <map>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <limits.h>

using namespace std;



EventObject::~EventObject(){
	Notify::Remove(this);
}

namespace Notify{
	typedef boost::signals2::signal< void (void* instance, int, boost::any) > NotifySignal;
	typedef map< boost::tuple<void*, int>, boost::shared_ptr<NotifySignal> > NotifySignalStore;

	//flag,  0=get, 1=autoCreate, 2=delete
	NotifySignalStore* GetAllSigs(int flag = 0){
		static NotifySignalStore* allSig =0;
		switch(flag){
			case 1:
				{
					if(!allSig){
						allSig = new NotifySignalStore();
					}
				}
				break;
			case 2:
				{
					if(allSig){
						allSig->clear();
						delete allSig;
						allSig = 0;
					}
				}
				break;
		}
		return allSig;
	}

	void Fire(void* instance, int msg, boost::any data){
		NotifySignalStore* all = GetAllSigs(0);
		if(all){
			NotifySignalStore::iterator it = all->find(boost::make_tuple(instance, msg) );
			if(it != all->end()){
				boost::shared_ptr<NotifySignal> sig =it->second;
				(*sig)(instance, msg, data);
			}
			if(msg != INT_MAX){
				NotifySignalStore::iterator it = all->find(boost::make_tuple(instance, INT_MAX) );
				if(it != all->end()){
					boost::shared_ptr<NotifySignal> sig =it->second;
					(*sig)(instance, msg, data);
				}
			}
		}
		
	}
	boost::signals2::connection Add(void* instance, NotifyCallback callback, int group, boost::signals2::connect_position pos){
		return Add(instance, INT_MAX, callback, group, pos);
	}
	boost::signals2::connection Add(void* instance, int msg, NotifyCallback callback, int group, boost::signals2::connect_position pos){
		NotifySignalStore* all = GetAllSigs(1);
		assert(all);
		boost::shared_ptr<NotifySignal> sig;
		NotifySignalStore::iterator it = all->find(boost::make_tuple(instance, msg));
		if(it == all->end()){
			sig.reset(new NotifySignal());
			(*all)[boost::make_tuple(instance, msg)] = sig;
		}else{
			sig = it->second;
		}
		if(group){
			return sig->connect(group, callback, pos);
		}
		return sig->connect(callback, pos);
	}
	void Remove(boost::signals2::connection con){
		con.disconnect();
	}
	void Remove(void* instance, int msg){
		NotifySignalStore* all = GetAllSigs(0);
		if(all){
			all->erase(boost::make_tuple(instance, msg));
		}
	}
	void Remove(void* instance){
		NotifySignalStore* all = GetAllSigs(0);
		if(all){
			vector<boost::tuple<void*, int> > vec;
			for(NotifySignalStore::iterator it = all->begin(); it!= all->end(); ++it){
				const boost::tuple<void*, int>& t = it->first;
				if(t.get<0>() == instance){
					vec.push_back(it->first);
				}
			}
			for(int i=0; i< vec.size(); ++i){
				all->erase(vec[i]);
			}
			if(all->empty()){
				GetAllSigs(2);
			}
		}
	}
};
